package ssen.mvc.base {
import avmplus.getQualifiedClassName;

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.utils.Dictionary;

import ssen.mvc.core.IContextView;
import ssen.mvc.core.IInjector;
import ssen.mvc.core.IMediator;
import ssen.mvc.core.IViewMap;

public class ViewMap implements IViewMap {
	private var contextView:IContextView;
	private var injector:IInjector;

	private var dic:Dictionary;

	public function ViewMap(contextView:IContextView, injector:IInjector) {
		this.contextView=contextView;
		this.injector=injector;

		dic=new Dictionary;

		setViewRegister(contextView);
	}

	private function setViewRegister(contextView:IContextView):void {
		var container:DisplayObjectContainer=contextView as DisplayObjectContainer;
		container.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, true);
	}

	private function unsetViewRegister(contextView:IContextView):void {
		var container:DisplayObjectContainer=contextView as DisplayObjectContainer;
		container.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, true);
	}

	private function addedToStageHandler(event:Event):void {
		var viewClass:Class=event.target.constructor;

		if (dic[viewClass] === undefined) {
			return;
		}

		var parent:DisplayObjectContainer=DisplayObject(event.target).parent;

		while (true) {
			if (parent is IContextView) {
				if (parent === this) {
					break;
				} else {
					return;
				}
			}

			parent=parent.parent;
		}

		new ViewManager(injector, event.target as DisplayObject, dic[viewClass]);
	}

	public function map(viewClass:Class, mediatorClass:Class=null):void {
		if (dic[viewClass] !== undefined) {
			throw new Error("mapped view class!!!");
		}

		dic[viewClass]=mediatorClass;
	}

	public function unmap(viewClass:Class):void {
		delete dic[viewClass];
	}

	public function create(viewClass:Class):Object {
		if (dic[viewClass] === undefined) {
			throw new Error("undefined this viewClass!!! " + getQualifiedClassName(viewClass));
		}

		var view:DisplayObject=new viewClass();
		injector.injectInto(view);
		new ViewManager(injector, view, dic[viewClass]);

		return view;
	}

	public function dispose():void {
		unsetViewRegister(contextView);
		contextView=null;
		dic=null;
		injector=null;
	}
}
}
import flash.display.DisplayObject;
import flash.events.Event;

import ssen.mvc.core.IInjector;
import ssen.mvc.core.IMediator;

class ViewManager {
	private var mediator:IMediator;
	private var view:DisplayObject;

	public function ViewManager(injector:IInjector, view:DisplayObject, mediatorClass:Class=null) {
		this.view=view;
		injector.injectInto(view);

		if (mediatorClass) {
			mediator=injector.instantiate(mediatorClass);
			mediator.setView(view);

			if (view.stage) {
				mediator.onRegister();
				view.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
			} else {
				view.addEventListener(Event.ADDED_TO_STAGE, addedToStage);
			}
		}
	}

	private function addedToStage(event:Event):void {
		view.removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
		mediator.onRegister();
		view.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
	}

	private function removedFromStage(event:Event):void {
		view.removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
		mediator.onRemove();

		mediator=null;
		view=null;
	}
}
